#include "codegenerator.h"
#include "syntaxtree.h"
#include "basicparser.h"
#include "parser.h"
#include "asmcmd.h"
#include "errors.h"
#include <map>
#include <utility>
#include <cstdlib>
// Here will be a body of code generator
// and generation functions from various headers
// 
namespace CCompiler
{
    template<typename T>
    Asm::Imm<T> imm(T val) { return Asm::Imm<T>(val); }
    
    typedef void(*GenFunction)(Generator &g);
    typedef std::pair<SymbolType, SymbolType> twoTypes;
    typedef std::pair<twoTypes, std::string> BinOpGenKey;
    typedef std::pair<SymbolType, std::string> UnaryOpGenKey;

    std::map<BinOpGenKey, GenFunction> binOpGen;
    std::map<UnaryOpGenKey, std::pair<GenFunction, bool> > unaryOpGen;
    std::map<UnaryOpGenKey, std::pair<GenFunction, bool> > postfixUnaryOpGen;

    Asm::Reg rEax("eax");
    Asm::Reg rEbx("ebx");
    Asm::Reg rEcx("ecx");
    Asm::Reg rEdx("edx");
    Asm::Reg rEsp("esp");
    Asm::Reg rEsi("esi");
    Asm::Reg rEdi("edi");
    Asm::Reg rEbp("ebp");
    Asm::Reg rAl("al");
    Asm::Reg rCl("cl");

    Asm::Reg rSt0("st0");
    Asm::Reg rSt1("st1");

    
    std::string opMov = "mov", opPush = "push", opPop = "pop", opMovzx = "movzx", opTest = "test",
        opAnd = "and", opOr = "or", opXor = "xor", opJmp = "jmp", opJe = "je", opJl = "jl",
        opJg = "jg", opJle = "jle", opJge = "jge", opJne = "jne", opJz = "jz", opJnz = "jnz",
        opSete = "sete", opSetl = "setl", opSetg = "setg", opSetle = "setle", opSetge = "setge",
        opSetne = "setne", opCall = "call", opRet = "ret", opAdd = "add", opSub = "sub", opImul = "imul",
        opIdiv = "idiv", opNeg = "neg", opNot = "not", opSar = "sar", opSal = "sal", opFld = "fld",
        opFild = "fild", opFist = "fist", opFistp = "fistp", opFstp = "fstp", opFadd = "fadd", opFsub = "fsub", 
        opFmul = "fmul", opFdiv = "fdiv", opFchs = "fchs", opFldz = "fldz", opFcom = "fcom", opFfree = "ffree",
        opFcomp = "fcomp", opCmp = "cmp", opInc="inc", opDec="dec"; 

    char* sizeDirs[] = 
    {
        0,
        "byte",
        "word",
        0,
        "dword",
        0,
        "fword",
        0,
        "qword",
    };

    std::map<SymbolType, std::string> manglingTypeTable;    
	void Generator::generateHeader()
	{
		outfile_ << 
			"format PE \n"
			"entry start\n"
            "include 'include\\macro\\import32.inc'\n"
            "data import\n"
            "    library msvcrt, 'MSVCRT.DLL'\n"
            "    import  msvcrt, printf, 'printf'\n"
            "end data\n";
	}

    std::string Generator::getStrLiteralName()
    {
        std::ostringstream stream;
        stream << literalCounter++ << "__literal";
        return mangling(stream.str(), stArray);
    }

    void Generator::addStrLiteral(std::string name, std::string str)
    {
        strLiterals.push_back(std::make_pair(name, str));        
    }

	void Generator::generateFooter()
    {
        for(std::vector<std::pair<std::string, std::string> >::iterator i = strLiterals.begin();
            i != strLiterals.end(); ++i)
        {
            outfile_ << i->first << " db ";
            for(std::string::iterator j = i->second.begin(); j != i->second.end(); ++j)
            {
                outfile_ << (int)(*j) << ", ";
            }
            outfile_ << 0 << std::endl;
        }
    }
    void Generator::genDb(std::string name, size_t size)
    {
        code_.push_back(new Asm::Db(name, size));
    }
    void Generator::genLabel(std::string name)
    {
        code_.push_back(new Asm::Label(name));
    }
    std::string Generator::getLabel()
    {
        std::ostringstream stream;
        stream << "L" << labelCounter++;
        return stream.str();
    }
    void Generator::genOp(std::string mnem)
    {
        code_.push_back(new Asm::Op(mnem));
    }
    std::string Generator::mangling(std::string name, SymbolType type)
    {
        return manglingTypeTable[type] + "$" + name;    
    }

    template<typename T>
    Asm::SizeDir sizeDir(size_t size, const T &arg)
    {
        return Asm::SizeDir(sizeDirs[size], new T(arg));
    }

    template<>
    Asm::SizeDir sizeDir(size_t size, const Asm::Reg &arg)
    {
        return Asm::SizeDir(sizeDirs[size], new Asm::OffsetReg(arg));
    }

    void Generator::generate()
    {
        for(SymTable::iterator it = symtable_.begin(); it != symtable_.end(); ++it)
        {   // reserve memory for global variables 
            if(it->second->getSymbolType() == stVariable)
            {
                std::string mname = mangling(it->first, it->second->getType()->getSymbolType());
                genDb(mname, std::max(((SymVariable *)it->second)->getSize(), (size_t)4));
            }                                                        
        }
        SymFunction *main = NULL;
        {
            Symbol *_main = symtable_.find("main");
            if(_main->getSymbolType() != stFunction || _main->getType()->getName() != "int()")
                throw Errors::CodeGenError("File must contain an entry point - int main()");
            main = (SymFunction *)_main;
        }
        genLabel("start");
        SynFunctionCall(new SynVal("main")).generate(*this);
        genOp(opPop, rEax);
        genOp(opRet);
        for(SymTable::iterator it = symtable_.begin(); it != symtable_.end(); ++it)
        {   // producing a code for functions
            if(it->second->getSymbolType() == stFunction)
            {
                functionHandler.currentFunction = (SymFunction *) it->second; 
                functionHandler.returnOffset = functionHandler.currentFunction->getParametersSize() + 4;
                functionHandler.deepestBlockBegin = 0;
                if(functionHandler.currentFunction->getResultType()->getSymbolType() == stVoid)
                    functionHandler.currentFunction->getBody()->addStatement(new SynStatementReturn(0));
                pushTable(functionHandler.currentFunction);
                genLabel(mangling(it->first, stFunction));
                genOp(opPush, rEbp);
                genOp(opMov, rEbp, rEsp);
                genOp(opAdd, rEbp, imm(4));
                functionHandler.currentFunction->getBody()->generate(*this);
                popTable();
            }                                                        
        }
        generateHeader();
        for(size_t i = 0; i < code_.size(); ++i)
            outfile_ << code_[i]->str() << std::endl;        
        generateFooter();
    }

    void SynStatementReturn::generate(Generator &g)
    {
        if(expr_)
        {
            expr_->generate(g);
            g.genOp(opPop, rEax);
            g.genOp(opMov, sizeDir(4, Asm::OffsetReg(rEbp).setAbsOffset(g.getReturnOffset())), rEax);
        }
        g.genOp(opMov, rEsp, rEbp);
        g.genOp(opMov, rEbp, sizeDir(4, Asm::OffsetReg(rEbp).setAbsOffset(-4)));
        g.genOp(opRet);
    }

    /* Work with stack in function call
        |  returned value   | <- this will be a result of expression
        | .... args ....    |
        | ^ Function Args ^ | <- we need to clean up to this point
        |-- return point -- | <- ebp always must point here(+4 for params, -4 for locals)
        |    stored ebp     | <- we need to restore it at return statement
        |  local variables  | <- they are BlockStatements problem
    */

    void SynFunctionCall::generate(Generator &g)
    {
        size_t reservedSpace = 0;
        Symbol *f = caller_->getType(g.accessTable());
        if(f->getSymbolType() == stFunctionPointer) f = ((SymFunctionPointer *)f)->getPointed();
        SymFunctionType *ft = (SymFunctionType *)f;
        g.genOp(opSub, rEsp, imm(ft->getResultType()->getSize()));
        for(ArgList::reverse_iterator it = arguments_.rbegin(); it != arguments_.rend(); ++it)
        {
            (*it)->generate(g);
            reservedSpace += (*it)->getType(g.accessTable())->getSize();
        }
        caller_->genLvalue(g);
        g.genOp(opPop, rEax);
        g.genOp(opCall, rEax);
        g.genOp(opAdd, rEsp, imm(reservedSpace)); // now only returned value in stack
    }

    Generator::~Generator()
    {
        for(size_t i = 0; i < code_.size(); ++i)
            delete code_[i];
    }

    void SynStatementBlock::generate(Generator &g)
    {
     
        g.pushTable(&tbl_);
        g.genOp(opSub, rEsp, imm(localsSize_));
        g.setDeepestBlockBegin(g.getDeepestBlockBegin() + localsSize_);
        for(std::vector<SynStatement *>::iterator i = content_.begin(); i != content_.end(); ++i)
            (*i)->generate(g);
        g.setDeepestBlockBegin(g.getDeepestBlockBegin() - localsSize_);
        g.genOp(opAdd, rEsp, imm(localsSize_));
        g.popTable();
    }

    void SynInt::generate(Generator &g)
    {
        g.genOp(opPush, imm(value_));
    }

    void SynStatementExpression::generate(Generator &g)
    {
        expr_->generate(g);
        if(expr_->getType(g.accessTable())->getSize())
            g.genOp(opPop, rEax);
    }
    void SynStatementPrintf::generate(Generator &g)
    {
        int stackOccupied = 0;
        for(std::vector<SynExpression*>::reverse_iterator i = args_.rbegin(); i != args_.rend(); ++i)
        {
            SymType *expr_type = (*i)->getType(g.accessTable());
            (*i)->generate(g);
            if(expr_type->getSymbolType() == stFloat)
            {
                g.genOp(opFld, sizeDir(4, rEsp));
                g.genOp(opSub, rEsp, imm(4));
                g.genOp(opFstp, sizeDir(8, rEsp));
                stackOccupied += 8;
            }
            else
                stackOccupied += expr_type->getSize();
        }
        g.genOp(opCall, Asm::Mem("printf"));
        g.genOp(opAdd, rEsp, imm(stackOccupied));
    }
    void SynString::generate(Generator &g)
    {
        std::string name = g.getStrLiteralName();
        g.addStrLiteral(name, value_);
        g.genOp(opPush, Asm::Offset(name));
    }

    void SynBinaryOp::generate(Generator &g)
    {
        first_->generate(g);
        second_->generate(g);
        SymType *t1 = first_->getType(g.accessTable()), *t2 = second_->getType(g.accessTable());
        SymbolType s1 = t1->getSymbolType(), s2 = t2->getSymbolType();
        BinOpGenKey key(twoTypes(s1, s2), binOp_);
        if(!binOpGen.count(key))
            throw Errors::CodeGenError("Binary operation not implemented :" + t1->getName() + binOp_ + t2->getName());
        binOpGen[key](g);
    }

    void SynUnaryOp::generate(Generator &g)
    {
        std::pair<GenFunction, bool> desc;
        SymType *t1 = first_->getType(g.accessTable());
        SymbolType s1 = t1->getSymbolType();
        UnaryOpGenKey key(s1, unOp_);
        if(postfix_)
        {
            if(!postfixUnaryOpGen.count(key))
                throw Errors::CodeGenError("Postfix unary operation not implemented :" + t1->getName() + unOp_);
            desc = postfixUnaryOpGen[key];        
        }
        else
        {
            if(!unaryOpGen.count(key))
                throw Errors::CodeGenError("Unary operation not implemented :" + unOp_ + t1->getName());
            desc = unaryOpGen[key];
        }
        if(desc.second)
            first_->genLvalue(g);
        else
            first_->generate(g);
        desc.first(g);        
    }

    void SynVal::generate(Generator &g)
    {
        Symbol *smbl = g.accessTable().find(identifier_);
        SymType *t = getType(g.accessTable());
        switch(smbl->getSymbolType())
        {
        case stFunctionParameter:
            g.genOp(opPush, sizeDir(t->getSize(), 
                Asm::OffsetReg(rEbp).setAbsOffset(((SymFunctionParameter*) smbl)->getOffset()+4)));
            break;
        case stLocalVariable:
            g.genOp(opPush, sizeDir(t->getSize(), 
                Asm::OffsetReg(rEbp).setAbsOffset(-(((SymLocalVariable*) smbl)->getOffset()+4))));
            break;
        case stVariable:
            g.genOp(opPush,
                sizeDir(t->getSize(), Asm::Mem(g.mangling(identifier_, t->getSymbolType()))));
            break;
        }
    }
    void SynVal::genLvalue(Generator &g)
    {
        Symbol *smbl = g.accessTable().find(identifier_);
        SymType *t = getType(g.accessTable());
        switch(smbl->getSymbolType())
        {
        case stFunctionParameter:
            g.genOp(opMov, rEax, rEbp);
            g.genOp(opAdd, rEax, imm(((SymFunctionParameter*) smbl)->getOffset()+4));
            g.genOp(opPush, rEax);
            break;
        case stLocalVariable:
            g.genOp(opMov, rEax, rEbp);
            g.genOp(opSub, rEax, imm(((SymLocalVariable*) smbl)->getOffset()+4));
            g.genOp(opPush, rEax);
            break;
        default:
            g.genOp(opPush, Asm::Offset(g.mangling(identifier_, t->getSymbolType())));
            break;
        }
    }

    void SynFloat::generate(Generator &g)
    {
        g.genOp(opPush, imm(value_));
    }

    void SynSizeof::generate(Generator &g)
    {
        g.genOp(opPush, imm(type_->getSize()));
    }
    void genAssign(Generator &g, size_t size)
    { // scalar assign
        g.genOp(opPop, rEbx);
        g.genOp(opPop, rEax);
        g.genOp(opMov, sizeDir(size, rEax), rEbx);
        g.genOp(opPush, rEbx);
    }

    void SynAssignOp::generate(Generator &g)
    {
        SymType *t1 = first_->getType(g.accessTable()), *t2 = second_->getType(g.accessTable());
        first_->genLvalue(g);
        if(binOp_ != "=")
        {
            BinOpGenKey key(twoTypes(t1->getSymbolType(), t2->getSymbolType()), AssignOp2BinOp[binOp_]);
            t2 = AvailableBinOpsAndHandlers[BinOpOnTypes(key.second, key.first)](first_, second_, g.accessTable());
            first_->generate(g);
            second_->generate(g);
            binOpGen[key](g);
        }
        else second_->generate(g);
        BinOpGenKey key(twoTypes(t1->getSymbolType(), t2->getSymbolType()), "=");
        genAssign(g, t1->getSize());
    }
        
    void SynCast::generate(Generator &g)
    {
        first_->generate(g);
        SymbolType st1 = first_->getType(g.accessTable())->getSymbolType(), st2 = toType_->getSymbolType();
        if(st1 == stFloat && st2 == stInt)
        {
            g.genOp(opFld, Asm::SizeDir(sizeDirs[4], new Asm::OffsetReg(rEsp)));
            g.genOp(opFistp, Asm::SizeDir(sizeDirs[4], new Asm::OffsetReg(rEsp)));
        }
        else if(st1 == stInt && st2 == stFloat)
        {
            g.genOp(opFild, Asm::SizeDir(sizeDirs[4], new Asm::OffsetReg(rEsp)));
            g.genOp(opFstp, Asm::SizeDir(sizeDirs[4], new Asm::OffsetReg(rEsp)));
        }
    }

    void SynDot::genCommon(Generator &g)
    {
        first_->genLvalue(g);
        g.genOp(opPop, rEax);
        SymTypeStruct *l = (SymTypeStruct *)first_->getType(g.accessTable());
        g.genOp(opMov, rEbx, imm(l->askMyOffset(l->getField(((SynVal *)second_)->getName()))));
        g.genOp(opAdd, rEax, rEbx);
    }
    void SynDot::generate(Generator &g)
    {
        genCommon(g);
        g.genOp(opPush, sizeDir(4, rEax));
    }
    void SynDot::genLvalue(Generator &g)
    {
        genCommon(g);
        g.genOp(opPush, rEax);
    }

    void SynIndexation::genCommon(Generator &g)
    {
        first_->genLvalue(g);
        second_->generate(g);
        g.genOp(opPop, rEbx);
        g.genOp(opMov, rEax, imm(((SymTypePointer *)first_->getType(g.accessTable()))->getPointed()->getSize()));
        g.genOp(opImul, rEbx);
        g.genOp(opPop, rEbx);
        g.genOp(opAdd, rEax, rEbx);
    }
    void SynIndexation::generate(Generator &g)
    {
        genCommon(g);
        g.genOp(opPush, sizeDir(((SymTypePointer *)first_->getType(g.accessTable()))->getPointed()->getSize(), rEax));
    }
    void SynIndexation::genLvalue(Generator &g)
    {
        genCommon(g);
        g.genOp(opPush, rEax);
    }
    void SynStatementFor::generate(Generator &g)
    {
        if(init_)
        {
            init_->getType(g.accessTable());
            init_->generate(g);
            g.genOp(opAdd, rEsp, imm(4));
        }
        std::string L1 = g.getLabel(), L2 = g.getLabel(), L3 = g.getLabel();
        g.pushLoop(L3, L2);
        g.genLabel(L1);
        if(condition_)
        {
            condition_->getType(g.accessTable());
            condition_->generate(g);
            g.genOp(opPop, rEax);
            g.genOp(opTest, rEax, rEax);
            g.genOp(opJz, Asm::Offset(L2));
        }
        if(body_) body_->generate(g);
        g.genLabel(L3);
        if(iter_)
        {
            iter_->getType(g.accessTable());
            iter_->generate(g);
            g.genOp(opAdd, rEsp, imm(4));
        }
        g.genOp(opJmp, Asm::Offset(L1));
        g.genLabel(L2);
        g.popLoop();
    }
    void SynStatementWhile::generate(Generator &g)
    {
        std::string L1 = g.getLabel(), L2 = g.getLabel();
        condition_->getType(g.accessTable());
        g.genLabel(L1);
        condition_->generate(g);
        g.genOp(opPop, rEax);
        g.genOp(opTest, rEax, rEax);
        g.genOp(opJz, Asm::Offset(L2));
        g.pushLoop(L1, L2);
        if(body_)
            body_->generate(g);
        g.genOp(opJmp, Asm::Offset(L1));
        g.popLoop();
        g.genLabel(L2);
    }
    void SynStatementDoWhile::generate(Generator &g)
    {
        std::string L1 = g.getLabel(), L2 = g.getLabel();
        condition_->getType(g.accessTable());
        g.genLabel(L1);
        if(body_) body_->generate(g);
        condition_->generate(g);
        g.genOp(opPop, rEax);
        g.genOp(opTest, rEax, rEax);
        g.genOp(opJnz, Asm::Offset(L1));
        g.genLabel(L2);        
    }

    void SynStatementIf::generate(Generator &g)
    {
        condition_->generate(g);
        condition_->getType(g.accessTable());
        g.genOp(opPop, rEax);
        g.genOp(opTest, rEax, rEax);
        if(!action_) return;
        std::string L1 = g.getLabel();
        g.genOp(opJz, Asm::Offset(L1));
        action_->generate(g);
        g.genLabel(L1);
    }
    void SynStatementIfWithElse::generate(Generator &g)
    {
        condition_->generate(g);
        condition_->getType(g.accessTable());
        std::string L2;
        if(elseAction_) L2 = g.getLabel();
        g.genOp(opPop, rEax);
        g.genOp(opTest, rEax, rEax);
        if(action_)
        {   std::string L1 = g.getLabel();
            g.genOp(opJz, Asm::Offset(L1));
            action_->generate(g);
            if(elseAction_) g.genOp(opJmp, Asm::Offset(L2));
            g.genLabel(L1);
        }
        if(elseAction_)
        {
            elseAction_->generate(g);
            g.genLabel(L2);
        }
    }
    void SynStatementBreak::generate(Generator &g)
    {
        g.genOp(opJmp, Asm::Offset(g.getLoopEnd()));
    }
    void SynStatementConinue::generate(Generator &g)
    {
        g.genOp(opJmp, Asm::Offset(g.getLoopBegin()));
    }

    namespace Generators
    {
        void loadTwoArgs2Reg(Generator &g)
        {
            g.genOp(opPop, rEbx);
            g.genOp(opPop, rEax);
        }
        void loadOneArg2Reg(Generator &g)
        {
            g.genOp(opPop, rEax);
        }

        void IntPlusInt(Generator &g)
        {
            loadTwoArgs2Reg(g);
            g.genOp(opAdd, rEax, rEbx);
            g.genOp(opPush, rEax);
        }
        void IntMulInt(Generator &g)
        {
             loadTwoArgs2Reg(g);
             g.genOp(opImul, rEbx);
             g.genOp(opPush, rEax);

        }
        void IntSubInt(Generator &g)
        {
            loadTwoArgs2Reg(g);
            g.genOp(opSub, rEax, rEbx);
            g.genOp(opPush, rEax);
        }

        void IntDivInt(Generator &g)
        {
            loadTwoArgs2Reg(g);
            g.genOp(opXor, rEdx, rEdx);
            g.genOp(opIdiv, rEbx);
            g.genOp(opPush, rEax);
        }

        void IntModInt(Generator &g)
        {
            loadTwoArgs2Reg(g);
            g.genOp(opXor, rEdx, rEdx);
            g.genOp(opIdiv, rEbx);
            g.genOp(opPush, rEdx);
        }

        void NegInt(Generator &g)
        {
            loadOneArg2Reg(g);
            g.genOp(opNeg, rEax);
            g.genOp(opPush, rEax);
        }

        void NotInt(Generator &g)
        {
            loadOneArg2Reg(g);
            g.genOp(opTest, rEax, rEax);
            g.genOp(opSete, rAl);
            g.genOp(opMovzx, rEax, rAl);
            g.genOp(opPush, rEax);
        }

        void IntSalInt(Generator &g)
        {
            g.genOp(opPop, rEcx);
            loadOneArg2Reg(g);
            g.genOp(opSal, rEax, rCl);
            g.genOp(opPush, rEax);
        }
        void IntCmpInt(Generator &g, std::string setx)
        {
            loadTwoArgs2Reg(g);
            g.genOp(opCmp, rEax, rEbx);
            g.genOp(setx, rAl);
            g.genOp(opMovzx, rEax, rAl);
            g.genOp(opPush, rEax);
        }
        void IntSarInt(Generator &g)
        {
            g.genOp(opPop, rEcx);
            loadOneArg2Reg(g);
            g.genOp(opSar, rEax, rCl);
            g.genOp(opPush, rEax);
        }

        void PrefixInt(Generator &g, std::string mnem)
        {
            loadOneArg2Reg(g);
            g.genOp(mnem, sizeDir(4, rEax));
            g.genOp(opPush, sizeDir(4, rEax));
        }
        void PostfixInt(Generator &g, std::string mnem)
        {
            loadOneArg2Reg(g);
            g.genOp(opPush, sizeDir(4, rEax));
            g.genOp(mnem, sizeDir(4, rEax));
        }

        void PrefixIncInt (Generator &g) { PrefixInt (g, opInc); }
        void PostfixIncInt(Generator &g) { PostfixInt(g, opInc); }
        void PrefixDecInt (Generator &g) { PrefixInt (g, opDec); }
        void PostfixDecInt(Generator &g) { PostfixInt(g, opDec);  }                     

        void IntLessInt(Generator &g)
        {
            IntCmpInt(g, opSetl);        
        }
        void IntLessEqualInt(Generator &g)
        {
            IntCmpInt(g, opSetle);
        }
        void IntGreaterInt(Generator &g)
        {
            IntCmpInt(g, opSetg);
        }
        void IntGreaterEqualInt(Generator &g)
        {
            IntCmpInt(g, opSetge);
        }
        void IntEqualInt(Generator &g)
        {
            IntCmpInt(g, opSete);
        }
        void IntNotEqualInt(Generator &g)
        {
            IntCmpInt(g, opSetne);
        }                         
        void ComplementInt(Generator &g)
        {
            loadOneArg2Reg(g);
            g.genOp(opNot, rEax);
            g.genOp(opPush, rEax);
        }
        void IntAndInt(Generator &g)
        {
            loadTwoArgs2Reg(g);
            g.genOp(opAnd, rEax, rEbx);
            g.genOp(opPush, rEax);
        }
        void IntOrInt(Generator &g)
        {
            loadTwoArgs2Reg(g);
            g.genOp(opOr, rEax, rEbx);
            g.genOp(opPush, rEax);
        }
        void IntXorInt(Generator &g)
        {
            loadTwoArgs2Reg(g);
            g.genOp(opXor, rEax, rEbx);
            g.genOp(opPush, rEax);
        }
        void IntLogicalOrInt(Generator &g)
        {
            loadTwoArgs2Reg(g);
            std::string L1 = g.getLabel(), L2 = g.getLabel(), L3 = g.getLabel();
            g.genOp(opTest, rEax, rEax);
            g.genOp(opJnz, Asm::Offset(L1));
            g.genOp(opTest, rEbx, rEbx);
            g.genOp(opJz, Asm::Offset(L2));             
            g.genLabel(L1);
            g.genOp(opMov, rEax, imm(1));
            g.genOp(opJmp, Asm::Offset(L3));
            g.genLabel(L2);
            g.genOp(opMov, rEax, imm(0));
            g.genLabel(L3);
            g.genOp(opPush, rEax);
        }

        void IntLogicalAndInt(Generator &g)
        {
            loadTwoArgs2Reg(g);
            std::string L1 = g.getLabel(), L2 = g.getLabel();
            g.genOp(opTest, rEax, rEax);
            g.genOp(opJz, Asm::Offset(L1));
            g.genOp(opTest, rEbx, rEbx);
            g.genOp(opJz, Asm::Offset(L1));             
            g.genOp(opMov, rEax, imm(1));
            g.genOp(opJmp, Asm::Offset(L2));
            g.genLabel(L1);
            g.genOp(opMov, rEax, imm(0));
            g.genLabel(L2);
            g.genOp(opPush, rEax);
        }

        void FloatCommonAriphmeticsFloat(Generator &g, const std::string &mnem)
        {
            g.genOp(opFld, sizeDir(4, Asm::OffsetReg(rEsp).setAbsOffset(4)));
            g.genOp(mnem, sizeDir(4, Asm::OffsetReg(rEsp)));
            g.genOp(opAdd, rEsp, imm(4));
            g.genOp(opFstp, sizeDir(4, Asm::OffsetReg(rEsp)));

        }
        void FloatPlusFloat(Generator &g)
        {
            FloatCommonAriphmeticsFloat(g, opFadd);
        }        
        void FloatMinusFloat(Generator &g)
        {
            FloatCommonAriphmeticsFloat(g, opFsub);
        }
        void FloatMulFloat(Generator &g)
        {
            FloatCommonAriphmeticsFloat(g, opFmul);
        }
        void FloatDivFloat(Generator &g)
        {
            FloatCommonAriphmeticsFloat(g, opFdiv);
        }

        void FloatCmpFloat(Generator &g, std::string mnem)
        {
            g.genOp(opFld, sizeDir(4, Asm::OffsetReg(rEsp).setAbsOffset(4)));
            g.genOp(opFcomp, sizeDir(4, rEsp));
            g.genOp(mnem, rAl);
            g.genOp(opAdd, rEsp, imm(4));
            g.genOp(opMovzx, rEax, rAl);
            g.genOp(opMov, Asm::OffsetReg(rEsp), rEax);
        }

        void FloatLessFloat(Generator &g)
        {
            FloatCmpFloat(g, opSetl);        
        }
        void FloatLessEqualFloat(Generator &g)
        {
            FloatCmpFloat(g, opSetle);
        }
        void FloatGreaterFloat(Generator &g)
        {
            FloatCmpFloat(g, opSetg);
        }
        void FloatGreaterEqualFloat(Generator &g)
        {
            FloatCmpFloat(g, opSetge);
        }
        void FloatEqualFloat(Generator &g)
        {
            FloatCmpFloat(g, opSete);
        }
        void FloatNotEqualFloat(Generator &g)
        {
            FloatCmpFloat(g, opSetne);
        }   

        void NotFloat(Generator &g)
        {
            g.genOp(opFld, sizeDir(4, rEsp));
            g.genOp(opFldz);
            g.genOp(opFcom, rSt1);
            g.genOp(opSete, rAl);
            g.genOp(opMovzx, rEax, rAl);
            g.genOp(opMov, sizeDir(4, rEsp), rEax);
            g.genOp(opFfree, rSt0);
        }
        void NegFloat(Generator &g)
        {
            g.genOp(opFld, sizeDir(4, rEsp));
            g.genOp(opFchs);
            g.genOp(opFstp, sizeDir(4, rEsp));
        }

    }
}
namespace __InitializeCodegenerator
{    
    using namespace CCompiler;
    void binGen(SymbolType s1, SymbolType s2, std::string op, GenFunction f)
    {
        binOpGen[BinOpGenKey(twoTypes(s1, s2), op)] = f;
    }
    void unaryGen(SymbolType s1, std::string op, GenFunction f, bool needLvalue = false)
    {
        unaryOpGen[UnaryOpGenKey(s1, op)] = std::make_pair(f, needLvalue);
    }
    void pUnaryGen(SymbolType s1, std::string op, GenFunction f, bool needLvalue = false)
    {
        postfixUnaryOpGen[UnaryOpGenKey(s1, op)] = std::make_pair(f, needLvalue);
    }
    void initialize()
    {
        using namespace CCompiler;
        std::map<SymbolType, std::string> &mtt = manglingTypeTable;
        mtt[stInt] = "int";
        mtt[stFloat] = "float";
        mtt[stPointer] = "ptr";
        mtt[stFunctionPointer] = "fptr";
        mtt[stFunctionType] = mtt[stFunction] = "func";
        mtt[stArray] = "arr";
        mtt[stStruct] = "struct";
        using namespace Generators;
        binGen(stInt, stInt, "+", IntPlusInt);
        binGen(stInt, stInt, "*", IntMulInt);
        binGen(stInt, stInt, "-", IntSubInt);
        binGen(stInt, stInt, "/", IntDivInt);
        binGen(stInt, stInt, "%", IntModInt);
        binGen(stInt, stInt, "<<", IntSalInt);
        binGen(stInt, stInt, ">>", IntSarInt);
        binGen(stInt, stInt, "<", IntLessInt);
        binGen(stInt, stInt, ">", IntGreaterInt);
        binGen(stInt, stInt, "<=", IntLessEqualInt);
        binGen(stInt, stInt, ">=", IntGreaterEqualInt);
        binGen(stInt, stInt, "==", IntEqualInt);
        binGen(stInt, stInt, "!=", IntNotEqualInt);
        binGen(stInt, stInt, "|", IntOrInt);
        binGen(stInt, stInt, "&", IntAndInt);
        binGen(stInt, stInt, "^", IntXorInt);
        binGen(stInt, stInt, "||", IntLogicalOrInt);
        binGen(stInt, stInt, "&&", IntLogicalAndInt);
        binGen(stFloat, stFloat, "+", FloatPlusFloat);        
        binGen(stFloat, stFloat, "-", FloatMinusFloat);
        binGen(stFloat, stFloat, "*", FloatMulFloat);
        binGen(stFloat, stFloat, "/", FloatDivFloat);  
        binGen(stFloat, stFloat, "<", FloatLessFloat);
        binGen(stFloat, stFloat, ">", FloatGreaterFloat);
        binGen(stFloat, stFloat, "<=", FloatLessEqualFloat);
        binGen(stFloat, stFloat, ">=", FloatGreaterEqualFloat);
        binGen(stFloat, stFloat, "==", FloatEqualFloat);
        binGen(stFloat, stFloat, "!=", FloatNotEqualFloat);
        unaryGen(stInt, "++", PrefixIncInt, true);
        pUnaryGen(stInt, "++", PostfixIncInt, true);        
        unaryGen(stInt, "--", PrefixDecInt, true);
        pUnaryGen(stInt, "--", PostfixDecInt, true);
        unaryGen(stInt, "-", NegInt);
        unaryGen(stFloat, "-", NegFloat);
        unaryGen(stInt, "!", NotInt);
        unaryGen(stFloat, "!", NotFloat);
        unaryGen(stInt, "~", ComplementInt);
    }
}